using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace FoundationLib.AddIns.Constraints.Visitors
{
	/// <summary>
	/// Represents a visitor evaluating OCL collection statements
	/// </summary>
	public class CollectionVisitor : RegexVisitor
	{
		private const string PATTERN = @"([^-\( ]+)->([^\(]+)\(([^\)]{0,})?\)";

		/// <summary>
		/// Creates a new collection visitor
		/// </summary>
		public CollectionVisitor()
			: base(PATTERN)
		{
		}

		private string ConvertOperation(string root, string operation, string argument)
		{
			switch(operation)
			{
				case "count":
					return root + ".Where(x => x == " + argument + ").Count()";
				case "includes":
					return root + ".Contains(" + argument + ")";
				case "excludes" :
					return "!" + root + ".Contains(" + argument + ")";
				case "includesAll":
					return root + ".Where(x => " + argument + ".Contains(x)).Count() == " + argument + ".Count()";
				case "excludesAll":
					return root + ".Where(x => " + argument + ".Contains(x)).Count() == 0";
				case "isEmpty":
					return root + ".Count() == 0";
				case "notEmpty":
					return root + ".Count() > 0";
				case "size":
					return root + ".Count()";
				case "first":
					return root + ".First()";
				case "last":
					return root + ".Last()";
				case "indexOf":
					return root + ".IndexOf(" + argument + ")";
				case "union":
					return root + ".Union(" + argument + ")";
				case "at":
					return root + ".ElementAt(" + argument + ")";
				default:
					return root;
			}
		}

		/// <summary>
		/// Evaluates regular expession matches
		/// </summary>
		/// <returns>The result of the evaluation</returns>
		/// <param name="match">The regular expression match</param>
		protected override string Evaluate(Match match)
		{
			string argument = match.Groups.Count <= 3 ? null : match.Groups[3].Value;
			return this.ConvertOperation(match.Groups[1].Value, match.Groups[2].Value, argument);
		}
	}
}
